﻿using System;
using System.Collections.Generic;


namespace SpiritEngine
{
    public class GameScreen
    {
        // MEMBER VARIABLES
        // ------------------------------------------------------------------------------------------------------------------------

        // Set to internal so the Engine can access it without allowing
        // other classes to set the Engine.  The Engine property of the
        // GameScreen class is set when the game screen is passed into
        // the Engine's PushGameScreen() method.  This is to ensure that the
        // integrity of our GameScreen stack is maintained.
        internal Engine m_Engine = null;

        bool m_bLoaded = false;

        List<AComponent> m_listComponents = new List<AComponent>();


        // CONSTRUCTORS
        // ------------------------------------------------------------------------------------------------------------------------

        public GameScreen()
        {

        } // end GameScreen::GameScreen()


        // PRIVATE/PROTECTED METHODS
        // ------------------------------------------------------------------------------------------------------------------------

        protected virtual void Load()
        {
            foreach (AComponent c in m_listComponents)
                c.LoadComponent();

        } // end void GameScreen::Load()


        // METHODS
        // ------------------------------------------------------------------------------------------------------------------------

        public void AddComponent(AComponent Component)
        {
            if (!m_listComponents.Contains(Component))
            {
                m_listComponents.Add(Component);
                Component.ParentGameScreen = this;
                Component.LoadComponent();
                PutComponentInOrder(Component);
            }

        } // end void GameScreen::AddComponent(AComponent)

        public void RemoveComponent(string Name)
        {
            AComponent c = this[Name];
            RemoveComponent(c);

        } // end void GameScreen::RemoveComponent(string)

        // The components are stored in their draw order, so it is easy to loop
        // through them and draw them in the correct order without having to sort
        // them every time they are drawn.
        public void PutComponentInOrder(AComponent Component)
        {
            if (m_listComponents.Contains(Component))
            {
                m_listComponents.Remove(Component);

                int i = 0;

                // Iterate through the components in order until we find one with
                // a higher or equal draw order, and insert the component at that position.
                for (i = 0; i < m_listComponents.Count; i++)
                {
                    if (m_listComponents[i].DrawOrder >= Component.DrawOrder)
                    {
                        break;
                    }
                }

                m_listComponents.Insert(i, Component);
            }
        } // end void GameScreen::PutComponentInOrder(AComponent)


        public void RemoveComponent(AComponent Component)
        {
            if (Component != null && m_listComponents.Contains(Component))
            {
                m_listComponents.Remove(Component);
                Component.ParentGameScreen = null;
            }

        } // end void GameScreen::RemoveComponent(AComponent)

        public void LoadGameScreen()
        {
            if (m_bLoaded)
                return;

            Load();

            m_bLoaded = true;

        } // end void GameScreen::LoadGameScreen()

        public virtual void Update()
        {
            // Copy the list of components so the game won't crash if the original
            // list is modified while we're updating.
            List<AComponent> updating = new List<AComponent>();

            foreach (AComponent c in m_listComponents)
                updating.Add(c);

            foreach (AComponent c in updating)
                c.Update();
        } // end void GameScreen::Update()

        public virtual void Draw()
        {
            foreach (AComponent c in m_listComponents)
                c.Draw();

        } // end void GameScreen::Draw()



        // DEBUG METHODS
        // ------------------------------------------------------------------------------------------------------------------------

#if (DEBUG)
        // put all debug methods in here...
#endif


        // PROPERTIES
        // ------------------------------------------------------------------------------------------------------------------------

        // Allow for components to be retrieved with the [] operator, ie:
        // Component c = gameScreenInstance["Component"];
        public AComponent this[string Name]
        {
            get
            {
                foreach (AComponent Component in m_listComponents)
                {
                    if (Component.Name == Name)
                    {
                        return Component;
                    }
                }

                return null;
            }
        } // end property [string Name]

        public Engine Engine
        {
            get
            {
                return m_Engine;
            }
        } // end property Engine

        public bool Loaded
        {
            get
            {
                return m_bLoaded;
            }
        } // end property Loaded


        // EVENTS
        // ------------------------------------------------------------------------------------------------------------------------



    } // end class GameScreen
}
